package guava.study.lyh.concurrent;

/**
 * 作者 yaohua.liu
 * 日期 2014-11-26 12:16
 * 包名 guava.study.lyh.concurrent
 * 说明 ...
 */
/*
 * Copyright (C) 2009 The Guava Authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import com.google.common.collect.Lists;
import com.google.common.util.concurrent.AbstractIdleService;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.common.util.concurrent.Service;
import org.junit.Test;

import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import static org.junit.Assert.*;

/**
 * Tests for {@link com.google.common.util.concurrent.AbstractIdleService}.
 *
 * @author Chris Nokleberg
 * @author Ben Yu
 */
public class AbstractIdleServiceTest2 {

    @Test
    public void testStart() {
        TestService service = new TestService();
        assertEquals(0, service.startUpCalled);
        service.startAsync().awaitRunning();
        assertEquals(1, service.startUpCalled);
        assertEquals(Service.State.RUNNING, service.state());
       // ASSERT.that(service.transitionStates).has().exactly(Service.State.STARTING).inOrder();
    }

    @Test
    public void testStart_failed() {
        final Exception exception = new Exception("deliberate");
        TestService service = new TestService() {
            @Override protected void startUp() throws Exception {
                super.startUp();
                throw exception;
            }
        };
        assertEquals(0, service.startUpCalled);
        try {
            service.startAsync().awaitRunning();
            fail();
        } catch (RuntimeException e) {
            assertSame(exception, e.getCause());
        }
        assertEquals(1, service.startUpCalled);
        assertEquals(Service.State.FAILED, service.state());
        //ASSERT.that(service.transitionStates).has().exactly(Service.State.STARTING).inOrder();
    }

    @Test
    public void testStop_withoutStart() {
        TestService service = new TestService();
        service.stopAsync().awaitTerminated();
        assertEquals(0, service.startUpCalled);
        assertEquals(0, service.shutDownCalled);
        assertEquals(Service.State.TERMINATED, service.state());
        //ASSERT.that(service.transitionStates).isEmpty();
    }

    @Test
    public void testStop_afterStart() {
        TestService service = new TestService();
        service.startAsync().awaitRunning();
        assertEquals(1, service.startUpCalled);
        assertEquals(0, service.shutDownCalled);
        service.stopAsync().awaitTerminated();
        assertEquals(1, service.startUpCalled);
        assertEquals(1, service.shutDownCalled);
        assertEquals(Service.State.TERMINATED, service.state());
       // ASSERT.that(service.transitionStates).has().exactly(Service.State.STARTING, Service.State.STOPPING).inOrder();
    }

    @Test
    public void testStop_failed() {
        final Exception exception = new Exception("deliberate");
        TestService service = new TestService() {
            @Override protected void shutDown() throws Exception {
                super.shutDown();
                throw exception;
            }
        };
        service.startAsync().awaitRunning();
        assertEquals(1, service.startUpCalled);
        assertEquals(0, service.shutDownCalled);
        try {
            service.stopAsync().awaitTerminated();
            fail();
        } catch (RuntimeException e) {
            assertSame(exception, e.getCause());
        }
        assertEquals(1, service.startUpCalled);
        assertEquals(1, service.shutDownCalled);
        assertEquals(Service.State.FAILED, service.state());
      //  ASSERT.that(service.transitionStates).has().exactly(Service.State.STARTING, Service.State.STOPPING).inOrder();
    }

    @Test
    public void testServiceToString() {
        AbstractIdleService service = new TestService();
        assertEquals("TestService [NEW]", service.toString());
        service.startAsync().awaitRunning();
        assertEquals("TestService [RUNNING]", service.toString());
        service.stopAsync().awaitTerminated();
        assertEquals("TestService [TERMINATED]", service.toString());
    }

    @Test
    public void testTimeout() throws Exception {
        // Create a service whose executor will never run its commands
        Service service = new TestService() {
            @Override
            protected Executor executor() {
                return new Executor() {
                    @Override
                    public void execute(Runnable command) {
                    }
                };
            }
        };
        try {
            service.startAsync().awaitRunning(1, TimeUnit.MILLISECONDS);
            fail("Expected timeout");
        } catch (TimeoutException e) {
           // ASSERT.that(e.getMessage()).contains(Service.State.STARTING.toString());
        }
    }

    private static class TestService extends AbstractIdleService {
        int startUpCalled = 0;
        int shutDownCalled = 0;
        final List<State> transitionStates = Lists.newArrayList();

        @Override
        protected void startUp() throws Exception {
            assertEquals(0, startUpCalled);
            assertEquals(0, shutDownCalled);
            startUpCalled++;
            assertEquals(State.STARTING, state());
        }

        @Override
        protected void shutDown() throws Exception {
            assertEquals(1, startUpCalled);
            assertEquals(0, shutDownCalled);
            shutDownCalled++;
            assertEquals(State.STOPPING, state());
        }

        @Override
        protected Executor executor() {
            transitionStates.add(state());
            return MoreExecutors.sameThreadExecutor();
        }
    }
}